package com.wutianyi.anagram;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;

public class HandlerImpl {

	private static ThreadLocal<FileChannel> fileChannelLocal = new ThreadLocal<FileChannel>();

	private ExecutorService executor;

	private String file;
	private Map<String, Index> indexs;

	private final int MAX_THREAD_SIZE = 100;

	public HandlerImpl(String file, Map<String, Index> _indexs) {
		executor = Executors.newFixedThreadPool(MAX_THREAD_SIZE,
				new SearchThreadFactory());
		this.file = file;
		this.indexs = _indexs;
	}

	public boolean search(String searchWord) throws InterruptedException,
			ExecutionException {
		char[] anagram = searchWord.toCharArray();
		Arrays.sort(anagram);
		String anagramWord = new String(anagram);
		Index index = indexs.get(anagramWord);

		if (null == index) {
			return false;
		}
		List<String> words = index.getCache();
		if(null != words) {
			if(words.contains(searchWord)) {
				return true;
			}
		}
		
		Future<Boolean> result = executor.submit(new SearchTask(index,
				searchWord));
		return result.get();
	}

	private class SearchThreadFactory implements ThreadFactory {

		@Override
		public Thread newThread(Runnable r) {
			return new SearchThread(r);
		}

	}

	private class SearchTask implements Callable<Boolean> {

		private Index index;
		private String searchWord;

		public SearchTask(Index _index, String _searchWord) {
			this.index = _index;
			this.searchWord = _searchWord;
		}

		@Override
		public Boolean call() throws Exception {
			FileChannel fc = fileChannelLocal.get();
			if (null == fc || null == index) {
				return false;
			}
			ByteBuffer bb = ByteBuffer.allocate(index.end - index.start);
			fc.read(bb, index.start);

			List<String> words = Arrays.asList(new String(bb.array())
					.split(","));
			index.setCache(words);
			if (words.contains(searchWord)) {
				return true;
			}

			return false;
		}
	}

	private class SearchThread extends Thread {
		private FileInputStream input;
		private FileChannel fc;

		public SearchThread(Runnable _runnable) {
			super(_runnable);

		}

		@Override
		public void run() {
			fc = fileChannelLocal.get();
			if (null == fc) {
				try {
					input = new FileInputStream(file);
				} catch (FileNotFoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				fc = input.getChannel();

				fileChannelLocal.set(fc);
			}

			super.run();

		}

		@Override
		public void destroy() {
			if (null != input) {
				try {
					fc.close();
					input.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

	}

}
